console.inspectEnable = true;
const WebApp = require('webapp');
const bodyParser = require("middleware").bodyParser;
const app = WebApp.createApp();
app.use(bodyParser.json());
app.use(WebApp.static('./public'));

// 全局资源初始化
// device
const { devManager } = require('./data/device');
// lightKV DataBase
const { sceneDB } = require('./data/lkv_db');
// socket.io server
const { initSocketIO } = require('./common/socket_server');
const socketIO = initSocketIO(app);
socketIO.on('connection', (socket) => {
	console.info('socket connection')
	socket.on('init', () => {
		init();
	});
	socket.on('init-scene', () => {
		initScene();
	});
	socket.on('change-scene-devices', (data) => {  // {delete_id: string, add_id: string};
		changeSceneDevice(data)
	});
	socket.on('change-scene-settings', (data) => {  // {label: string, points: [0, 100] }
		if (humidityDev) {
			initGetHumidity(humidityDev.devid)
		}
		humidity_water_scene.settings = data;
		updateSceneDB();
		socketIO.emit('sceneSettings', humidity_water_scene.settings);
	});
	socket.on('send-device-message', (params) => {  // {devid: string, data: any};
		const { devid, data } = params;
		devManager.sendDeviceInfo(devid, data).catch((err) => {
			emitError(err | '操作失败！')
		})
	});
})

let humidity_water_scene = sceneDB.get('humidity_water');
let humidityDev = null; // 场景湿度探测设备
let waterDev = null; // 场景浇水设备
let watering = false;  // 是否正在浇水
let t = 0; // 浇水期间加快获取湿度的定时器

function init() {
	emitDevices();
	initScene();
}

function emitDevices() {
	socketIO.emit('devices', [...devManager.devMap.values()]);
}

function emitError(msg) {
	socketIO.emit('error', msg);
}

async function initScene() {
	if (!humidity_water_scene) {
		humidity_water_scene = {
			devids: [],
			settings: {
				label: '',
				points: [0, 100]
			}
		}
		updateSceneDB();
	}
	for (const devid of humidity_water_scene.devids) {
		const dev = devManager.devMap.get(devid)
		if (!dev) {
			continue;
		}
		if (!devManager.controllerMap.has(dev.devid)) {
			generateDevController(dev.devid).then(() => {
				setSceneDevice(dev)
				socketIO.emit('join', dev);
				if (getDeviceType(dev) === 'humidity') {
					initGetHumidity(dev.devid)
				}
			}).catch(error => {
				emitError(error);
			})
		} else {
			setSceneDevice(dev);
			if (getDeviceType(dev) === 'humidity') {
				initGetHumidity(dev.devid)
			}
			socketIO.emit('join', dev); // 其他用户进入应用后同步设备状态
		}
	}
}

async function changeSceneDevice(data) {
	const { add_id, delete_id } = data;
	if (delete_id) {
		deleteSceneDev(delete_id); 	// 删除上一个设备
		devManager.deleteController(delete_id) // 删除设备控制对象
	}
	// 替换新设备
	if (!add_id) {
		return emitError('设备切换失败！')
	}
	const dev = devManager.devMap.get(add_id);
	generateDevController(add_id).then(() => {
		humidity_water_scene.devids.push(dev.devid);
		updateSceneDB();
		setSceneDevice(dev);
		if (getDeviceType(dev) === 'humidity') {
			initGetHumidity(dev.devid)
		}
		socketIO.emit('join', dev);
	}).catch((error) => {
		emitError(error);
	})
}

devManager.on('join', async (dev) => {
	if (isSceneDev(dev.devid)) {
		// 说明加入的设备是当前场景设备
		generateDevController(dev.devid).then(() => {
			socketIO.emit('join', dev);
			if (isSceneDev(dev.devid) && getDeviceType(dev) === 'water') {
				// 主动获取浇水器的状态
				devManager.sendDeviceInfo(dev.devid, {
					"method": "get",
					"obj": ["watering"]
				})
			} else if (isSceneDev(dev.devid) && getDeviceType(dev) === 'humidity') {
				initGetHumidity(dev.devid)
			}
		}).catch((error) => {
			emitError(error)
		})
	}
	emitDevices();
});
devManager.on('lost', (dev) => {
	if (isSceneDev(dev.devid)) {
		socketIO.emit('lost', dev);
		if (getDeviceType(dev) === 'humidity') {
			clearInterval(t);
			t = 0
		}
	}
  emitDevices();
});

devManager.on('error', (data) => {
	emitError(data)
})

// 构建设备控制对象
function generateDevController(devid) {
	return new Promise((resolve, reject) => {
		const dev = devManager.devMap.get(devid);
		devManager.generateController(devid).then((controller) => {
			controller.on('message', (data) => {
				console.info('meessage: ', data);
				const points = humidity_water_scene.settings.points;
				if (isSceneDev(devid) && getDeviceType(dev) === 'humidity') {
					socketIO.emit('humidity', Number(data.data.soil_humidity.toFixed(1))); // 0-100
					if (!waterDev) {
						return;
					}
					if (data.data.soil_humidity < points[0] && !watering) {
						startWater(); // 浇水
					} else if (data.data.soil_humidity >= points[0] && watering) {
						stopWater(); // 停水
					}
				} else if (getDeviceType(dev) === 'water') {
					// watering = data.data.watering === 'ON';
					if (data.data.watering === 'ON' && watering && t === 0 && humidityDev) {
						setHumidityTimer(1000);
					} else if (data.data.watering === 'OFF' && !watering && t) {
						clearInterval(t);
						t = 0
					}
				}
			});
			resolve(controller);
		}).catch(() => {
			reject(`应用缺少控制${dev.alias}的权限！`);
		})
	})
}

// 开始浇水
function startWater() {
	watering = true;
	devManager.sendDeviceInfo(waterDev.devid, { method: 'set', 'watering': 'ON' }).catch((error) => {
		emitError(error)
	})
}

// 停止浇水
function stopWater() {
	watering = false;
	devManager.sendDeviceInfo(waterDev.devid, { method: 'set', 'watering': 'OFF' }).catch((error) => {
		emitError(error)
	})
}

// 开启湿度探测定时器，浇水期间加快获取湿度实时值
function setHumidityTimer(s) {
	const controller = devManager.controllerMap.get(humidityDev.devid)
	if (controller) {
		t = setInterval(() => {
			controller.send({
				method: "get",
				obj: ["soil_humidity"]
			}, undefined, 3);
		}, s);
	}
}

// 获取设备类型（临时判断）
function getDeviceType(dev) {
	if (!dev) {
		return;
	}
	if (dev.report.type === 'device' && dev.report.name === '土壤湿度') {
		return 'humidity'
	} else if (dev.report.type === 'device' && dev.report.name === '智能浇水') {
		return 'water'
	} else {
		return 'device'
	}
}

// 是否是场景设备
function isSceneDev(devid) {
	return humidity_water_scene.devids.findIndex((id) => (id === devid)) >= 0
}

// 更新浇水场景数据库
function updateSceneDB() {
	sceneDB.set('humidity_water', humidity_water_scene);
}

function deleteSceneDev(devid) {
	humidity_water_scene.devids = humidity_water_scene.devids.filter((id) => {
		return id !== devid
	})
	updateSceneDB();
}

// 设置场景设备
function setSceneDevice(dev) {
	const type = getDeviceType(dev);
	if (type === 'humidity') {
		humidityDev = dev
	} else {
		waterDev = dev
	}
}

function initGetHumidity(devid) {
	devManager.sendDeviceInfo(devid, {
		method: "get",
		obj: ["soil_humidity"]
	}).catch((error) => {
		console.error('get soil_humidity error.');
		// socketIO.emit('error', 'error')
	})
}

app.start();
require('iosched').forever();
